/**
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 2 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY. 
 * See the GNU General Public License for more details.
 * 
 * Copyright (C) 2011 CellObject.net
 */
package net.cellobject.javacodeformatter.editor;

import java.io.IOException;
import java.io.LineNumberReader;
import java.io.PrintWriter;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import net.cellobject.javacodeformatter.log.FormatterLog;

/**
 * The editor model for a property file.
 */
public class PropertyFile extends PropertyElement {
	private PropertyCategory unnamedCategory;

	private final List<PropertyCategory> categories;

	private final List<PropertyFileListener> listeners;

	public PropertyFile(final String content) {
		super(null);
		categories = new ArrayList<PropertyCategory>();
		listeners = new ArrayList<PropertyFileListener>();
		final LineNumberReader reader = new LineNumberReader(new StringReader(content));
		try {
			unnamedCategory = new PropertyCategory(this, reader);
			while (true) {
				reader.mark(1);
				final int ch = reader.read();
				if (ch == -1) {
					break;
				}
				reader.reset();
				categories.add(new PropertyCategory(this, reader));
			}
		} catch (final IOException e) {
			FormatterLog.logError(e);
		}
	}

	@Override
	public PropertyElement[] getChildren() {
		final List<PropertyElement> children = new ArrayList<PropertyElement>();
		children.addAll(unnamedCategory.getEntries());
		children.addAll(categories);
		return children.toArray(new PropertyElement[children.size()]);
	}

	public void addCategory(final PropertyCategory category) {
		addCategory(categories.size() + unnamedCategory.getEntries().size(), category);
	}

	public void addCategory(final int index, final PropertyCategory category) {
		if (!categories.contains(category)) {
			categories.add(index - unnamedCategory.getEntries().size(), category);
			categoryAdded(category);
		}
	}

	public void removeCategory(final PropertyCategory category) {
		if (categories.remove(category)) {
			categoryRemoved(category);
		}
	}

	@Override
	public void removeFromParent() {
		// Nothing to do.
	}

	void addPropertyFileListener(final PropertyFileListener listener) {
		if (!listeners.contains(listener)) {
			listeners.add(listener);
		}
	}

	void removePropertyFileListener(final PropertyFileListener listener) {
		listeners.remove(listener);
	}

	void keyChanged(final PropertyCategory category, final PropertyEntry entry) {
		final Iterator<PropertyFileListener> iter = listeners.iterator();
		while (iter.hasNext()) {
			iter.next().keyChanged(category, entry);
		}
	}

	void valueChanged(final PropertyCategory category, final PropertyEntry entry) {
		final Iterator<PropertyFileListener> iter = listeners.iterator();
		while (iter.hasNext()) {
			iter.next().valueChanged(category, entry);
		}
	}

	void nameChanged(final PropertyCategory category) {
		final Iterator<PropertyFileListener> iter = listeners.iterator();
		while (iter.hasNext()) {
			iter.next().nameChanged(category);
		}
	}

	void entryAdded(final PropertyCategory category, final PropertyEntry entry) {
		final Iterator<PropertyFileListener> iter = listeners.iterator();
		while (iter.hasNext()) {
			iter.next().entryAdded(category, entry);
		}
	}

	void entryRemoved(final PropertyCategory category, final PropertyEntry entry) {
		final Iterator<PropertyFileListener> iter = listeners.iterator();
		while (iter.hasNext()) {
			iter.next().entryRemoved(category, entry);
		}
	}

	void categoryAdded(final PropertyCategory category) {
		final Iterator<PropertyFileListener> iter = listeners.iterator();
		while (iter.hasNext()) {
			iter.next().categoryAdded(category);
		}
	}

	void categoryRemoved(final PropertyCategory category) {
		final Iterator<PropertyFileListener> iter = listeners.iterator();
		while (iter.hasNext()) {
			iter.next().categoryRemoved(category);
		}
	}

	public String asText() {
		final StringWriter stringWriter = new StringWriter(2000);
		final PrintWriter writer = new PrintWriter(stringWriter);
		unnamedCategory.appendText(writer);
		final Iterator<PropertyCategory> iter = categories.iterator();
		while (iter.hasNext()) {
			writer.println();
			iter.next().appendText(writer);
		}
		return stringWriter.toString();
	}
}
